﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FCMGAAI
{
    public class GA1
    {
        public FCM1 coba;
        public int jumlahIndividu;
        public int panjangKromosom;
        public int nomorGenerasi;
        public int jumlahGenerasi;
        public int jumlahInduk;
        public int jumlahCrossover;
        public double fitness;
        public double fitnessTotal;
        public double batasAtasInitPop;
        public double batasBawahInitPop;
        public double peluangKum;
        public double ProbCrossover;
        public double ProbMutasi;
        public double xk;
        public double xkAtas;
        public double xkBawah;
        public double xkMutasi;
        public double Jm_Algen;
        public double fitness_Algen;
        public int[] bilAcak;
        public int[] range;
        public int[] indukCrossover;
        public double[] encoding_temp;
        public double[] peluang;
        public double[] peluangKumulatif;
        public double[] bilAcak2;
        public double[] crossover_temp1;
        public double[] crossover_temp2;
        public double[] kromosom_Algen;
        public double[] bilAcak3;
        public double[] mutasi_temp;
        public double[,] kromosom;
        public double[,] child1;
        public double[,] child2;
        public double[,] indukMutasi;
        List<double> pusatCluster_temp = new List<double>();
        List<populasiBaru> popBaru = new List<populasiBaru>();
        List<List<double>> indukMutasi_temp = new List<List<double>>();
        Random rand = new Random();
        public String outputPusatCluster, regenerasiOutput;
        public String[] anggotaa;
        public int[] letakk;
        public bool isRunned = false;
        public int[] clusterhasilfcm;

        public GA1(ref FCM1 _FCM)
        {

            coba = _FCM;

        }

        public void ConstructAlgen(int jmlPopulasi, int jmlGenerasi, double nilaiPc, double nilaiPm)
        {
            jumlahIndividu = jmlPopulasi;
            jumlahGenerasi = jmlGenerasi;
            ProbCrossover = nilaiPc;
            ProbMutasi = nilaiPm;
            encoding();
        }

        public void encoding()
        {
            panjangKromosom = coba.JumlahCluster * coba.panjangKolomParameterData;
            kromosom = new double[jumlahIndividu, panjangKromosom];


            for (int i = 0; i < coba.JumlahCluster; i++)
            {
                for (int j = 0; j < coba.panjangKolomParameterData; j++)
                {
                    pusatCluster_temp.Add(coba.MpusatCluster[i, j]);
                    //      outputPusatCluster += coba.MpusatCluster[i,j]+"#";
                }
                // outputPusatCluster += "\r\n";
            }


            batasAtasInitPop = pusatCluster_temp.Max();
            batasBawahInitPop = pusatCluster_temp.Min();

            //MessageBox.Show(outputPusatCluster+"\r\nNilai Max :"+batasAtasInitPop+"\r\nNilai Min :"+batasBawahInitPop);

            Random random1 = new Random();
            Random TrueRandom = new Random((int)DateTime.Now.Ticks & (0x0000FFFF + random1.Next())); ;
            double randomizer = 0.0;

            for (int i = 0; i < jumlahIndividu; i++)
            {
                for (int j = 0; j < panjangKromosom; j++)
                {
                    randomizer = (TrueRandom.Next() % (batasAtasInitPop * 1000)) / 1000;
                    if (randomizer < batasBawahInitPop)
                    {
                        randomizer = randomizer + batasBawahInitPop;
                    }

                    kromosom[i, j] = randomizer;
                    //outputPusatCluster += (kromosom[i, j])+ " ";
                }
                //outputPusatCluster += "\r\n";
            }
            //MessageBox.Show(outputPusatCluster);
        }


        public void evaluasi()
        {
            double JMskrng;
            //cobaJM = coba.HitungfungsiObjektif();
            encoding_temp = new double[panjangKromosom];

            for (int i = 0; i < jumlahIndividu; i++)
            {
                for (int krom = 0; krom < panjangKromosom; krom++) //panjangkromosom = cluster * atribut
                {
                    encoding_temp[krom] = kromosom[i, krom];
                }

                //memasukkan nilai inisialisasi populasi ke dalam matrik pusatCluster

                int count = 0;
                for (int k = 0; k < coba.JumlahCluster; k++)
                {
                    for (int j = 0; j < coba.panjangKolomParameterData; j++)
                    {
                        coba.MpusatCluster[k, j] = encoding_temp[count];
                        count++;
                    }
                }

                JMskrng = coba.HitungfungsiObjektif();
                popBaru.Add(new populasiBaru() { kromosombaru = encoding_temp, fObjektifbaru = JMskrng });
                fitness = (1 / JMskrng);
                fitnessTotal += fitness;

            }


            //cobaJMbaru = coba.HitungfungsiObjektif();


            //MessageBox.Show("Fungsi Objektif : \r\n"+outputPusatCluster);
        }

        public void seleksi()
        {
            bilAcak = new int[jumlahIndividu];
            peluang = new double[jumlahIndividu];
            peluangKumulatif = new double[jumlahIndividu];
            indukCrossover = new int[jumlahIndividu];
            range = new int[100];

            //menghitung peluang kumulatif tiap individu di populasi awal
            for (int i = 0; i < jumlahIndividu; i++)
            {
                peluang[i] = fitness / fitnessTotal;
                peluang[i] = Math.Round(peluang[i], 3);
                peluang[i] = peluang[i] * 1000;
                peluangKum = peluangKum + peluang[i];
                peluangKumulatif[i] = peluangKum;
            }

            int jumlahInduk_temp = jumlahIndividu / 2;
            if (jumlahInduk_temp % 2 == 0)
            {
                jumlahInduk = jumlahInduk_temp;
            }
            else
            {
                jumlahInduk = jumlahInduk_temp + 1;
            }

            for (int i = 0; i < jumlahInduk; i++)
            {
                bilAcak[i] = rand.Next(1, 1000);
                for (int j = 0; j < jumlahIndividu; j++)
                {
                    if (bilAcak[i] <= peluangKumulatif[j])
                    {
                        indukCrossover[i] = j;
                        break;
                    }
                }
            }
        }



        public void crossover()
        {
            jumlahCrossover = jumlahInduk / 2;
            bilAcak2 = new double[jumlahCrossover];
            child1 = new double[jumlahInduk, panjangKromosom];
            child2 = new double[jumlahInduk, panjangKromosom];
            indukMutasi = new double[jumlahInduk, panjangKromosom];
            crossover_temp1 = new double[panjangKromosom];
            crossover_temp2 = new double[panjangKromosom];

            for (int i = 0; i < jumlahCrossover; i++)
            {
                int titikCrossover = rand.Next(1, panjangKromosom - 1);
                bilAcak2[i] = rand.Next(100);
                bilAcak2[i] = bilAcak2[i] / 100;
                int parent1 = indukCrossover[i * 2];
                int parent2 = indukCrossover[(i * 2) + 1];

                //mengecek apakah bilangan random kurang dari Pc
                if (bilAcak2[i] < ProbCrossover)
                {
                    //proses crossover
                    for (int krom = 0; krom < panjangKromosom; krom++)
                    {
                        if (krom < titikCrossover)
                        {
                            child1[i, krom] = kromosom[parent1, krom];
                            child2[i, krom] = kromosom[parent2, krom];
                        }
                        else
                        {
                            child1[i, krom] = kromosom[parent2, krom];
                            child2[i, krom] = kromosom[parent1, krom];
                        }

                        indukMutasi[(i * 2), krom] = child1[i, krom];
                        indukMutasi[((i * 2) + 1), krom] = child2[i, krom];
                    }
                }
                else
                {
                    for (int krom = 0; krom < panjangKromosom; krom++)
                    {
                        child1[i, krom] = kromosom[parent1, krom];
                        child2[i, krom] = kromosom[parent2, krom];

                        indukMutasi[(i * 2), krom] = child1[i, krom];
                        indukMutasi[((i * 2) + 1), krom] = child2[i, krom];
                    }
                }
            }
        }

        public void mutasi()
        {

            //MessageBox.Show("indukmutasi : " + indukMutasi.Length.ToString());
            kromosom_Algen = new double[panjangKromosom];
            mutasi_temp = new double[panjangKromosom];
            int b = 2;
            double r = rand.NextDouble();
            int cekRumus = rand.Next(2);
            bilAcak3 = new double[jumlahIndividu];

            //menentukan kromosom yang akan dikenai mutasi
            for (int i = 0; i < jumlahInduk; i++)
            {
                indukMutasi_temp.Add(new List<double>());

                //membangkitkan bilangan random 0.00 sampai 0.99
                bilAcak3[i] = rand.Next(100);
                bilAcak3[i] = bilAcak3[i] / 100;

                //mengecek apakah bilangan random kurang dari Pm
                if (bilAcak3[i] < ProbMutasi)
                {
                    int titikMutasi = rand.Next(panjangKromosom);
                    for (int krom = 0; krom < panjangKromosom; krom++)
                    {
                        indukMutasi_temp[i].Add(indukMutasi[i, krom]);

                        if (krom == titikMutasi)
                        {
                            //menentukan gen yang akan dimutasi
                            xk = indukMutasi[i, krom];
                        }
                    }

                    //menentukan batas atas kromosom ke-i
                    xkAtas = indukMutasi_temp[i].Max();
                    //menentukan batas bawah kromosom ke-i
                    xkBawah = indukMutasi_temp[i].Min();
                    if (cekRumus == 0)
                    {
                        xkMutasi = xk + ((xkAtas - xk) * r * Math.Pow((1 - (nomorGenerasi / jumlahGenerasi)), b));
                        xkMutasi = Math.Round(xkMutasi, 2);
                    }
                    else
                    {
                        xkMutasi = xk - ((xk - xkBawah) * r * Math.Pow((1 - (nomorGenerasi / jumlahGenerasi)), b));
                        xkMutasi = Math.Round(xkMutasi, 2);
                    }
                    //memasukkan gen hasil mutasi ke dalam kromosom
                    for (int krom = 0; krom < panjangKromosom; krom++)
                    {
                        if (krom == titikMutasi)
                        {
                            indukMutasi[i, krom] = xkMutasi;
                        }
                    }
                }
            }

            //populasi hasil mutasi
            for (int i = 0; i < jumlahInduk; i++)
            {
                for (int krom = 0; krom < panjangKromosom; krom++)
                {
                    mutasi_temp[krom] = indukMutasi[i, krom];
                }


                //memasukkan nilai populasi hasil mutasi ke dalam matrik coba.MpusatCluster
                int count = 0;
                for (int k = 0; k < coba.JumlahCluster; k++)
                {
                    for (int j = 0; j < coba.panjangKolomParameterData; j++)
                    {
                        coba.MpusatCluster[k, j] = mutasi_temp[count];
                        count++;
                    }
                }
                double JMsekarang;
                JMsekarang = coba.HitungfungsiObjektif();
                popBaru.Add(new populasiBaru() { kromosombaru = (double[])mutasi_temp.Clone(), fObjektifbaru = JMsekarang });

            }

            for (int i = 0; i < jumlahIndividu; i++)
            {
                for (int krom = 0; krom < panjangKromosom; krom++)
                {
                    kromosom[i, krom] = popBaru[i].kromosombaru[krom];
                    kromosom_Algen[krom] = popBaru[0].kromosombaru[krom];
                }
                Jm_Algen = popBaru[0].fObjektifbaru;
                fitness_Algen = 1 / Jm_Algen;
            }
        }

        public void regenerasi()
        {
            //clusterhasilfcm = new int[coba.letak.Length];
            //Array.Copy(coba.letak,clusterhasilfcm,coba.letak.Length);
            //clusterhasilfcm = coba.letak;
            clusterhasilfcm = coba.letak;
            nomorGenerasi = 1;
            coba.SetMDerajatKeanggotaanAwal();
            for (int i = nomorGenerasi; i <= jumlahGenerasi; i++)
            {
                evaluasi();
                seleksi();
                crossover();
                mutasi();

                peluangKum = 0;
                fitnessTotal = 0;
                popBaru.Clear();
                nomorGenerasi++;

                coba.updateMatrikDerajatKeanggotaan();
                coba.SetAnggotaCluster();
                anggotaa = coba.NamaLabel.ToArray();

                letakk = coba.letak;
            }

            int count = 0;
            for (int k = 0; k < coba.JumlahCluster; k++)
            {
                for (int j = 0; j < coba.panjangKolomParameterData; j++)
                {
                    coba.MpusatCluster[k, j] = kromosom_Algen[count];
                    count++;
                }
            }
            coba.updateMatrikDerajatKeanggotaan();
            coba.SetAnggotaCluster();
            Finishing();
        }


        public void Finishing()
        {
            isRunned = true;
            ShareVariable.isGARunned = true;
            ShareVariable.MatriksUdariFCMGA = new double[coba.MderajatKeanggotaan.GetLength(0), coba.MderajatKeanggotaan.GetLength(1)];
            ShareVariable.MatriksPusatClusterFCMGA = new double[coba.MpusatCluster.GetLength(0), coba.MpusatCluster.GetLength(1)];
            for (int i = 0; i < coba.MderajatKeanggotaan.GetLength(0); i++)
            {
                for (int j = 0; j < coba.MderajatKeanggotaan.GetLength(1); j++)
                {
                    ShareVariable.MatriksUdariFCMGA[i, j] = coba.MderajatKeanggotaan[i, j];
                }
            }

            for (int i = 0; i < coba.MpusatCluster.GetLength(0); i++)
            {
                for (int j = 0; j < coba.MpusatCluster.GetLength(1); j++)
                {
                    ShareVariable.MatriksPusatClusterFCMGA[i, j] = coba.MpusatCluster[i, j];
                }
            }

        }

        struct populasiBaru
        {
            public double[] kromosombaru;
            public double fObjektifbaru;
        }

    }
}